package com.spzx.common.rabbit.config;

import com.alibaba.fastjson2.JSON;
import com.spzx.common.rabbit.entity.GuiguCorrelationData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ReturnedMessage;
import org.springframework.amqp.rabbit.connection.CorrelationData;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.event.ApplicationReadyEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.TimeUnit;

/**
 * 消息确认配置类
 */
@Slf4j
@Configuration
public class RabbitInitConfigApplicationListener implements ApplicationListener<ApplicationReadyEvent> {
    @Autowired
    RabbitTemplate rabbitTemplate;

    @Autowired
    RedisTemplate redisTemplate;

    @Override
    public void onApplicationEvent(ApplicationReadyEvent event) {
        setupCallbacks();
    }

    private void setupCallbacks() {
        rabbitTemplate.setConfirmCallback((correlationData, ack, cause) -> {

            if (ack) {
                //消息到交换器成功
                log.info("交换机收到消息了" + correlationData);
            } else {
                //消息到交换器失败
                log.error("交换机没有收到消息：{}", cause);

                //执行消息重发
                retrySendMsg(correlationData);
            }
        });

        rabbitTemplate.setReturnsCallback(returned -> {
            log.info("returned=" + returned);
            Object correlationId = returned.getMessage().getMessageProperties().getHeader("spring_returned_message_correlation");
            String correlationDataStr = (String) redisTemplate.opsForValue().get(correlationId);
            GuiguCorrelationData correlationData = JSON.parseObject(correlationDataStr, GuiguCorrelationData.class);

            //todo 方式一:如果不考虑延迟消息重发 直接返回
            if(correlationData.isDelay()){
                return;
            }

            //执行消息重发
            retrySendMsg(correlationData);
        });
    }

    private void retrySendMsg(CorrelationData correlationData) {
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        GuiguCorrelationData guiguCorrelationData = (GuiguCorrelationData) correlationData;
        int retryCount = guiguCorrelationData.getRetryCount();
        if (retryCount >= 3) {
            //超过最大重试次数
            log.error("生产者超过最大重试次数，将失败的消息存入数据库用由人工处理；给管理员发送邮件；给管理员发送短信；");
            return;
        }
        log.info("消息重试"+retryCount);

        guiguCorrelationData.setRetryCount(++retryCount);
        redisTemplate.opsForValue().set(guiguCorrelationData.getId(),
                JSON.toJSONString(guiguCorrelationData), 10, TimeUnit.MINUTES);

        //todo 方式二：如果是延迟消息，依然需要设置消息延迟时间
        if (guiguCorrelationData.isDelay()) {
            //延迟消息
            rabbitTemplate.convertAndSend(guiguCorrelationData.getExchange(),
                    guiguCorrelationData.getRoutingKey(),
                    guiguCorrelationData.getMessage(),
                    message -> {
                        message.getMessageProperties().setDelay(guiguCorrelationData.getDelayTime() * 1000);
                        return message;
                        },
                    guiguCorrelationData);
        } else {
            //普通消息
            rabbitTemplate.convertAndSend(guiguCorrelationData.getExchange(),
                    guiguCorrelationData.getRoutingKey(),
                    guiguCorrelationData.getMessage(),
                    guiguCorrelationData);
        }

    }
}
